package com.gitee.gateway.core.utils;

import java.util.List;
import java.util.concurrent.ForkJoinTask;
import java.util.concurrent.RecursiveAction;
import java.util.function.Consumer;

/**
 * 对列表进行拆分，交给子线程执行
 */
public class BatchTaskRunner<T> extends RecursiveAction {

    protected int threshold;
    protected List<T> taskList;
    Consumer<List<T>> action;

    /**
     * @param taskList  任务列表
     * @param threshold 每个线程处理的任务数
     * @param action    执行的任务
     */
    private BatchTaskRunner(List<T> taskList, int threshold, Consumer<List<T>> action) {
        threshold = Math.max(threshold, 1);
        this.taskList = taskList;
        this.threshold = threshold;
        this.action = action;
    }

    /**
     * 多线程批量执行任务
     *
     * @param taskList  任务列表
     * @param threshold 任务拆分粒度 = 每个线程处理的任务数
     * @param action    执行的任务
     */
    public static <T> void execute(List<T> taskList, int threshold, Consumer<List<T>> action) {
        if (taskList == null || taskList.isEmpty())
            return;
        new BatchTaskRunner<>(taskList, threshold, action).invoke();
    }

    @Override
    protected void compute() {
        if (taskList.size() <= threshold) {
            this.action.accept(taskList);
        } else {
            this.splitFromMiddle(taskList);
        }
    }

    /**
     * 任务中分
     *
     * @param list 任务列表
     */
    private void splitFromMiddle(List<T> list) {
        int middle = (int) Math.ceil(list.size() / 2.0);
        List<T> leftList = list.subList(0, middle);
        List<T> RightList = list.subList(middle, list.size());
        BatchTaskRunner<T> left = newInstance(leftList);
        BatchTaskRunner<T> right = newInstance(RightList);
        ForkJoinTask.invokeAll(left, right);
    }

    private BatchTaskRunner<T> newInstance(List<T> taskList) {
        return new BatchTaskRunner<>(taskList, threshold, action);
    }

    public static void main(String[] args) {
        List<Integer> tasks = List.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
        execute(tasks, tasks.size() / 5, list -> {
            System.out.println(Thread.currentThread().getName() + " --------> ");
            System.out.println(list);
        });
    }

}
